#ifndef NANE_DESERIALIZATIONFUNCTIONPROTOCOL_H
#   define  NANE_DESERIALIZATIONFUNCTIONPROTOCOL_H

#   include "nane/SerializeSystem/DeserializationTypeBase.h"
#   include "nane/core/stackstring.h"

#   include <cstring>

namespace nane
{
    template<typename F, typename TArg>
    class DeserializationFunctionProtocol
        : public DeserializationTypeBase
    {
    public:
        DeserializationFunctionProtocol( const char* _tag, F _functor )
            : m_tag( _tag )
            , m_functor( _functor )
        {
            
        }

    protected:
        template<typename TValue>
        bool Serialize( const char* _tag, TValue _data )
        {
            bool matched = (strcmp(m_tag, _tag) == 0);
            if( matched == true )
            {
                TArg value;
                if( Conversion::Convert(&value, _data) == false )
                {
                    return false;
                }
                else
                {
                    m_functor( value );
                }
            }
            return true;
        }

        bool Serialize( const char* _tag )
        {
            bool matched = (strcmp(m_tag, _tag) == 0);
            return !matched;
        }

        bool Serialize( const char* _tag, int32 _data )
        {
            return Serialize<int32>(_tag, _data);
        }

        bool Serialize( const char* _tag, uint32 _data )
        {
            return Serialize<uint32>(_tag, _data);
        }

        bool Serialize( const char* _tag, float _data )
        {
            return Serialize<float>(_tag, _data);
        }

        bool Serialize( const char* _tag, bool _data )
        {
            return Serialize<bool>(_tag, _data);
        }

        bool Serialize( const char* _tag, const char* _data )
        {
            return Serialize<const char*>(_tag, _data);
        }

    private:
        const char* m_tag;
        F m_functor;
    };

    // specialization for no parameters functor
    template<typename F>
    class DeserializationFunctionProtocol<F, void>
        : public DeserializationTypeBase
    {
    public:
        DeserializationFunctionProtocol( const char* _tag, F _functor )
            : m_tag( _tag )
            , m_functor( _functor )
        {

        }

    protected:
        template<typename TValue>
        bool Serialize( const char* _tag, TValue _data )
        {
            bool matched = (strcmp(m_tag, _tag) == 0);
            return !matched;
        }

        bool Serialize( const char* _tag )
        {
            bool matched = (strcmp(m_tag, _tag) == 0);
            if( matched == true )
            {
                m_functor();
            }
            return true;
        }

        bool Serialize( const char* _tag, int32 _data )
        {
            return Serialize<int32>(_tag, _data);
        }

        bool Serialize( const char* _tag, uint32 _data )
        {
            return Serialize<uint32>(_tag, _data);
        }

        bool Serialize( const char* _tag, float _data )
        {
            return Serialize<float>(_tag, _data);
        }

        bool Serialize( const char* _tag, bool _data )
        {
            return Serialize<bool>(_tag, _data);
        }

        bool Serialize( const char* _tag, const char* _data )
        {
            return Serialize<const char*>(_tag, _data);
        }

    private:
        const char* m_tag;
        F m_functor;
    };

    // specialization for const char*
    template<typename F>
    class DeserializationFunctionProtocol<F, const char*>
        : public DeserializationTypeBase
    {
    public:
        DeserializationFunctionProtocol( const char* _tag, F _functor )
            : m_tag( _tag )
            , m_functor( _functor )
        {

        }

    protected:
        template<typename TValue>
        bool Serialize( const char* _tag, TValue _data )
        {
            bool matched = (strcmp(m_tag, _tag) == 0);
            if( matched == true )
            {
                const char* value;
                if( Conversion::Convert(&value, _data) == false )
                {
                    return false;
                }
                else
                {
                    m_functor( value );
                }
            }
            return true;
        }

        bool Serialize( const char* _tag )
        {
            bool matched = (strcmp(m_tag, _tag) == 0);
            return !matched;
        }

        bool Serialize( const char* _tag, int32 _data )
        {
            StackString<16> value("%1");
            value << _data;
            return Serialize<const char*>(_tag, value.c_str());
        }

        bool Serialize( const char* _tag, uint32 _data )
        {
            StackString<16> value("%1");
            value << _data;
            return Serialize<const char*>(_tag, value.c_str());
        }

        bool Serialize( const char* _tag, float _data )
        {
            StackString<16> value("%1");
            value << _data;
            return Serialize<const char*>(_tag, value.c_str());
        }

        bool Serialize( const char* _tag, bool _data )
        {
            StackString<16> value("%1");
            value << _data;
            return Serialize<const char*>(_tag, value.c_str());
        }

        bool Serialize( const char* _tag, const char* _data )
        {
            return Serialize<const char*>(_tag, _data);
        }

    private:
        const char* m_tag;
        F m_functor;
    };

}   // namespace nane

#endif	// NANE_DESERIALIZATIONFUNCTIONPROTOCOL_H

